#pragma once
/*
 * Copyright © 2008 University of Houston
 * All rights reserved
 */

#include <stdio.h>

#include "session.h"
#include "filter.h"
#include "util.h"

using namespace std;

#define PKT_NO_VAL	-1

class timedHeader;
typedef long double 			pfloat;

class algorithm
{
public:
	algorithm() {};
	virtual ~algorithm() {};

	/*
	 * initializeVars will initialize any variables
	 * that the algorithm depends on.
	 */
	virtual void initializeVars();

	/*
	 * Initializes the session id and logfile parameters of our
	 * analyzerResultList.
	 *
	 * @param sessID The session id number
	 * @param logfile The name of the logfile
	 */
	void initializeResultList (int sessID, string logfile);

	/*
	 * StartAnalysis checks to make sure that the filter
	 * has specified either analysis or update. It also 
	 * updates lastPkt Time and initializes some of our
	 * variables
	 * @param th A pointer to the packet
	 * @param filtStatus Specified by the filter
	 */
	virtual void startAnalysis(timedHeader *th, int filtStatus);

	/*
	 * Analyze performs the actual analysis on the provided
	 * timedHeader. Meant to be over-ridden by subclasses.
	 */
	virtual void analyze();

	/*
	 * Preforms certain common updates to variables 
	 */
	virtual void finishAnalysis();

	/*
	 * @return analyzerResultList* A pointer to the vector of 
	 * results.
	 */
	analyzerResultList* getResultList();

	bool doAnalysis ()
	{
		if (filtRetStatus == ALG_DO_ANALYSIS)
			return true;
		return false;
	};

	bool doUpdate ()
	{
		if (filtRetStatus == ALG_DO_UPDATE)
			return true;
		return false;
	};

	bool doNothing ()
	{
		if (filtRetStatus == ALG_DO_NOTHING)
			return true;
		return false;
	};

	/*
	 * Called at the beginning of the Analyze method
	 * this method checks to make sure we have a last
	 * packet time and also that we are allowed to 
	 * update as given by the filter status
	 * @param th The timed header packet
	 * @param filtReturnStatus The status given by the filter
	 * @return true if algorithm should proceed, false otherwise
	 */
	bool doStartChecks (timedHeader *th, int filtReturnStatus);

	/*
	 * Updates lastPktTime at end of analysis code
	 */
	void updateLastPktTime ();
	
	// Override in child classes to re-define the name.
	virtual string getName() { return "Default"; }

	static algorithm* 	getAlg(int algID);
	static string 		getAlgName(int algID);
protected:
	analyzerResultList 	resultList;
	pfloat			lastPktTime;	// Time of last packet
	pfloat			ts;				// Timestamp of current packet
	pfloat			pktCount;		// Count of analyzed packets

	timedHeader*		latestPkt;		// The packet given to us
	int					filtRetStatus; 	// The filter's return status
};

class timeDiff : public algorithm
{
public:
	void initializeVars();
	void analyze();
	virtual string getName() { return "∆ Time"; }

private:
	pfloat		interval;		// Time diff since last packet
};

class avgDelay : public algorithm
{
public:
	void initializeVars();
	void analyze();
	virtual string getName() { return "Avg Delay"; }

private:
	pfloat 	avgDelay;		// Average Delay between packets
	pfloat 	totalDelay;		// Total delay of all packets
};

class stdDevDelay : public algorithm
{
public:
	void initializeVars();
	void analyze();

	virtual string getName() { return "Std Deviation"; }
private:
	pfloat 	interval;
	pfloat		sumOfValues;
	pfloat		sumOfSquaredValues;
	pfloat		stdDev;
};

/*
 * Meant to be used with filter 0. Tries to guess the number of hops in the
 * connection chain.
 */
class uberFilter : public algorithm
{
public:
	void initializeVars();
	void analyze();
	virtual string getName() { return "Uber"; }

private:
	void		printStats();			// Prints information
	void		updateTypeSpeed();		// Updates typing Speed info
	void		calculateSuspicion();	// Finds suspicion

	filter*		nearHop;		// Near Hop Filter
	filter*		userDelay;		// User Delay Filter
	filter*		command;		// Command Filter
	
	int			sensitivity;	// Sensitivity to detect new cmd
	int			speedMultiplier;// Sensitivity on new char

	pfloat interval;		// Time between current and last pkt

	pfloat typingSpeed;	// Speed of intra cmd typing
	pfloat lastCharTime;
	pfloat	charCount;		// Count of all chars typed
	pfloat	cmdCount;		// Count of all commands entered
	pfloat	totalCharTime;	// Typing time of all chars
	pfloat lastCmdTime; 	// Time of last cmd

	// Time (in seconds) between the last command being issued, and the
	// first character detected after that.
	// Example:
	// $ ls <enter> [timeA]
	// $ p[timeB]wd
	// TwitchTime = timeB-timeA
	pfloat twitchTime;		// Time between last cmd to next incoming

	pfloat nearHopRtt;		// RTT to nearest hop

	pfloat	guessRtt;		// Full RTT guess
	pfloat guessNumHops;	// Estimated Number of Hops
	pfloat	avgNumHops;		// Running avg of the guessNumHops

	pfloat totalNumHops;	// Total of all hop numbers
	pfloat guessCount;		// Number of guesses

	pfloat suspicion;		// Suspicion rating for this connection 0-100
	pfloat upperThreshold;	// Above all connections are 100 suspicion
	pfloat lowerThreshold;	// Below all connections are 0 suspicion
	pfloat stability;		// Number packets before stable
	pfloat rttCutOff;		// Exclude guess rtts larger than this
};

class zAlg1: public algorithm
{
public:
	void initializeVars();
	void analyze();
private:
	filter*		inBoundFilter;
	filter*		outBoundFilter;
	
};

